using DevExpress.ExpressApp.Blazor.Components.Models;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

namespace EasyXaf.Blazor.ImageViewers;

public partial class ImageViewerRenderer : IAsyncDisposable
{
    private string ContainerId { get; } = $"_{Guid.NewGuid()}";

    private IJSObjectReference JsModule { get; set; }

    private List<Func<Task>> JsActions { get; } = new();

    [Parameter]
    public ImageViewerModel Model { get; set; }

    [Inject]
    public IJSRuntime JSRuntime { get; set; }

    protected override void OnInitialized()
    {
        base.OnInitialized();
        ((IComponentModel)Model).Changed += Model_Changed;
    }

    private void Model_Changed(object sender, EventArgs e)
    {
        JsActions.Add(async () =>
        {
            await JsModule.InvokeVoidAsync("open", ContainerId, Model.ImageUrl);
        });

        StateHasChanged();
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);

        if (firstRender)
        {
            var jsModuleFile = "./_content/EasyXaf.Blazor.ImageViewers/ImageViewerRenderer.razor.js";
            JsModule = await JSRuntime.InvokeAsync<IJSObjectReference>("import", jsModuleFile);
            await JsModule.InvokeVoidAsync("init", ContainerId, new
            {
                showNavigator = true,
                showRotationControl = true,
                tileSources = new
                {
                    imageUrl = Model.ImageUrl
                },
            });
        }

        if (JsActions.Any())
        {
            foreach (var action in JsActions)
            {
                await action();
            }
            JsActions.Clear();
        }
    }

    public async ValueTask DisposeAsync()
    {
        ((IComponentModel)Model).Changed -= Model_Changed;

        try
        {
            if (JsModule != null)
            {
                await JsModule.InvokeVoidAsync("dispose", ContainerId);
            }
        }
        catch (JSDisconnectedException)
        {
        }

        if (JsModule != null)
        {
            await JsModule.DisposeAsync();
            JsModule = null;
        }

        GC.SuppressFinalize(this);
    }
}